package org.artofsolving.jodconverter.sample.web;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.List;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.artofsolving.jodconverter.OfficeDocumentConverter;
import org.artofsolving.jodconverter.document.DocumentFormat;

public class ConverterServlet extends HttpServlet {

  private static final long serialVersionUID = -591469426224201748L;
  private final Logger logger = Logger.getLogger(getClass().getName());

  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    boolean useOpenOffice = true;
    String urlP = request.getParameter("url");
    String f[] = urlP.split("\\$");
    String url = null;
    String outputExtension = null;
    if (f.length == 1) {
      url = f[0];
    } else if (f.length == 2) {
      url = f[0];
      outputExtension = f[1];
      if (outputExtension.endsWith("swf")) {
        outputExtension = "swf";
      }
    }

    System.out.println(urlP + "  " + url);
    String outputFileName = request.getParameter("outFile");
    String cache = request.getParameter("cache");
    //String outputExtension = request.getParameter("target");
    if (url != null) {
      //url = java.net.URLDecoder.decode(url);
    }
    String hash = MungPass(url);
    if (outputFileName != null) {
      outputFileName = java.net.URLDecoder.decode(outputFileName);
    } else {
      outputFileName = hash + ".swf";
    }

    if (outputExtension == null) {
      outputExtension = FilenameUtils.getExtension(outputFileName);
    }

    String baseName = url.substring((url.lastIndexOf('/') + 1));
    if (baseName.indexOf("?") > 0) {
      baseName = baseName.substring(0, baseName.indexOf("?"));
    }
    String inputExtension = FilenameUtils.getExtension(baseName);
    baseName = FilenameUtils.getBaseName(baseName);

    File outputFile = new File(this.getServletContext().getRealPath("") + File.separator + "docs" + File.separator + hash + "." + outputExtension);
    File inputFile = null;

    System.out.println(".." + outputExtension + " === " + inputExtension);
    System.out.println(getServletContext().getRealPath(""));
    if (!outputFile.exists()) {
      inputFile = new File(MungPass(url) + "." + inputExtension);
      if (!inputFile.exists()) {
        url = url.replaceAll(" ", "%20");
        System.out.println("encoded=" + url);
        FileOutputStream os = new FileOutputStream(inputFile);
        IOUtils.copy(new URL(url).openStream(), os);
        os.close();
      }
      System.out.println("==.." + outputExtension + " === " + inputExtension);

      if (inputExtension.equalsIgnoreCase("pdf") && "swf".equalsIgnoreCase(outputExtension)) {
        if (outputExtension.equals("swf")) {
          System.out.println(inputFile.getAbsolutePath() + " " + inputFile.exists());
          toSwf(inputFile, outputFile.getAbsolutePath(), hash, response);
          return;
        }
      }
    } else {

      if (outputExtension.equals("swf")) {
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().print("/docs/" + hash + ".swf");
        
      } else {
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename=" + baseName + "." + outputExtension);
        sendFile(outputFile, response);
      }
      return;
    }



    /* if (inputExtension.equalsIgnoreCase("pdf") && useOpenOffice) {
    //String exePath= this.getServletContext().getInitParameter(WebappContext.PARAMETER_TXConverter);
    String exePath = "C:\\myprojs\\ilookinto\\J\\ilookinto\\src\\site\\WEB-INF\\resources\\pdftohtml";
    if (System.getProperty("os.name").equalsIgnoreCase("Linux")) {
    exePath = "pdftohtml";
    }

    ProcessBuilder pb = new ProcessBuilder(new String[]{exePath,
    "-enc", "UTF-8", "-noframes", "-p", "-nomerge", "-nodrm", "-q",
    inputFile.getAbsolutePath(), hash + ".html"});
    Process p = pb.start();
    //_logger.debug("converting pdf begin " + inputFile.getAbsolutePath());
    try {

    if (p.waitFor() != 0) {
    } else {
    inputFile = new File(hash + ".html");
    }
    } catch (Exception e) {
    logger.severe(String.format("failed conversion: %s [%db] to %s; %s; input file: %s", inputExtension, inputFile.length(), outputExtension, e, inputFile.getName()));
    throw new ServletException("conversion failed", e);
    }
    }*/

    WebappContext webappContext = WebappContext.get(getServletContext());
    OfficeDocumentConverter converter = webappContext.getDocumentConverter();

    System.out.println("converting ...");
    try {
      DocumentFormat outputFormat = null;
      File tempFile = null;
      if (outputExtension.equals("swf")) {
        outputFormat = converter.getFormatRegistry().getFormatByExtension("pdf");
        tempFile = new File(hash + ".pdf");
      } else {
        outputFormat = converter.getFormatRegistry().getFormatByExtension(outputExtension);
      }

      long startTime = System.currentTimeMillis();
      if (!outputFile.exists()) {
        if (useOpenOffice || "swf".equals(outputExtension)) {
          System.out.println("before");
          converter.convert(inputFile, tempFile);
          System.out.println("before" + tempFile.getAbsolutePath());
        } else {
          System.out.println("damn ...");
          this.convertWithTxConverter(inputFile, outputFile, response.getOutputStream());
          //if (outputFile.getAbsolutePath().endsWith(".rtf")) return;
        }
      }
      if (outputExtension.equals("swf")) {
        toSwf(tempFile, outputFile.getAbsolutePath(), hash, response);
        return;
      }
      long conversionTime = System.currentTimeMillis() - startTime;
      //logger.info(String.format("successful conversion: %s [%db] to %s in %dms", inputExtension, inputFile.length(), outputExtension, conversionTime));
      response.setContentType("application/octet-stream");
      response.setHeader("Content-Disposition", "attachment; filename=" + baseName + "." + outputExtension);
      sendFile(outputFile, response);
    } catch (Exception exception) {
      //logger.severe(String.format("failed conversion: %s [%db] to %s; %s; input file: %s", inputExtension, inputFile.length(), outputExtension, exception, inputFile.getName()));
      throw new ServletException("conversion failed", exception);
    } finally {
      if (inputFile != null && ("false").equals(cache)) {
        inputFile.delete();
      }
      if (cache != null && ("false").equals(cache)) {
        outputFile.delete();
      }
    }
  }

  private String toSwf(File inputFile, String outputFile, String hash, HttpServletResponse response) throws ServletException {

    String exePath = "\"C:\\Program Files\\SWFTools\\pdf2swf\"";


    if (System.getProperty("os.name").equalsIgnoreCase("Linux")) {
      exePath = "pdf2swf";


    }
    //int start = inputFile.getAbsolutePath().lastIndexOf(".");

    try {
      ProcessBuilder pb = new ProcessBuilder(new String[]{exePath, "-f", "-q",
                inputFile.getAbsolutePath(), outputFile});
      Process p = pb.start();
      InputStream is = p.getInputStream();
      InputStreamReader isr = new InputStreamReader(is);
      BufferedReader br = new BufferedReader(isr);
      String line;





      while ((line = br.readLine()) != null) {
        //System.out.println(line);
      }


      //_logger.debug("converting pdf begin " + inputFile.getAbsolutePath());

      if (p.waitFor() != 0) {
        throw new Exception("swf convert probelm");


      } else {
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().print("/docs/" + hash + ".swf");
        //response.getWriter().print(outputFile);


        return outputFile;



      }
    } catch (Exception e) {
      //logger.severe(String.format("failed conversion: %s [%db] to %s; %s; input file: %s", inputExtension, inputFile.length(), outputExtension, e, inputFile.getName()));
      throw new ServletException("conversion failed", e);


    }
  }

  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    if (!ServletFileUpload.isMultipartContent(request)) {
      response.sendError(HttpServletResponse.SC_FORBIDDEN, "only multipart requests are allowed");




      return;




    }

    WebappContext webappContext = WebappContext.get(getServletContext());
    ServletFileUpload fileUpload = webappContext.getFileUpload();
    OfficeDocumentConverter converter = webappContext.getDocumentConverter();

    String outputExtension = FilenameUtils.getExtension(request.getRequestURI());

    FileItem uploadedFile;




    try {
      uploadedFile = getUploadedFile(fileUpload, request);




    } catch (FileUploadException fileUploadException) {
      throw new ServletException(fileUploadException);




    }
    if (uploadedFile == null) {
      throw new NullPointerException("uploaded file is null");




    }
    String inputExtension = FilenameUtils.getExtension(uploadedFile.getName());

    String baseName = FilenameUtils.getBaseName(uploadedFile.getName());
    File inputFile = File.createTempFile(baseName, "." + inputExtension);
    writeUploadedFile(
            uploadedFile, inputFile);
    File outputFile = File.createTempFile(baseName, "." + outputExtension);




    try {
      DocumentFormat outputFormat = converter.getFormatRegistry().getFormatByExtension(outputExtension);




      long startTime = System.currentTimeMillis();
      converter.convert(inputFile, outputFile);




      long conversionTime = System.currentTimeMillis() - startTime;
      logger.info(String.format("successful conversion: %s [%db] to %s in %dms", inputExtension, inputFile.length(), outputExtension, conversionTime));
      response.setContentType(outputFormat.getMediaType());
      response.setHeader("Content-Disposition", "attachment; filename=" + baseName + "." + outputExtension);
      sendFile(
              outputFile, response);




    } catch (Exception exception) {
      logger.severe(String.format("failed conversion: %s [%db] to %s; %s; input file: %s", inputExtension, inputFile.length(), outputExtension, exception, inputFile.getName()));




      throw new ServletException("conversion failed", exception);




    } finally {
      outputFile.delete();
      inputFile.delete();




    }
  }

  private void sendFile(File file, HttpServletResponse response) throws IOException {
    response.setContentLength((int) file.length());
    InputStream inputStream = null;




    try {
      inputStream = new FileInputStream(file);
      IOUtils.copy(inputStream, response.getOutputStream());




    } finally {
      IOUtils.closeQuietly(inputStream);




    }
  }

  private void writeUploadedFile(FileItem uploadedFile, File destinationFile) throws ServletException {
    try {
      uploadedFile.write(destinationFile);




    } catch (Exception exception) {
      throw new ServletException("error writing uploaded file", exception);




    }
    uploadedFile.delete();




  }

  private FileItem getUploadedFile(ServletFileUpload fileUpload, HttpServletRequest request) throws FileUploadException {
    @SuppressWarnings("unchecked")
    List<FileItem> fileItems = fileUpload.parseRequest(request);




    for (FileItem fileItem : fileItems) {
      if (!fileItem.isFormField()) {
        return fileItem;




      }
    }
    return null;




  }

  private void convertWithTxConverter(File inputFile, File outputFile, OutputStream outputStream) throws ServletException {

    //String exePath = "C:\\myprojs\\ilookinto\\prototypes\\TXConverter16\\TXConverter16\\bin\\Release\\TXConverter16.exe";
    String exePath = this.getServletContext().getInitParameter(WebappContext.PARAMETER_TXConverter);
    ProcessBuilder pb = new ProcessBuilder(new String[]{exePath,
              inputFile.getAbsolutePath(), outputFile.getAbsolutePath()});
    logger.info("converting tx begin " + inputFile.getAbsolutePath() + "  " + outputFile.getAbsolutePath());


    try {
      Process p = pb.start();
      StreamGobbler s2 = new StreamGobbler("stderror", p.getErrorStream());
      s2.start();
      // if (!outputFile.getAbsolutePath().endsWith(".rtf")) {
      StreamGobbler s1 = new StreamGobbler("stdin", p.getInputStream());
      s1.start();
      //} else {
      //  IOUtils.copy(p.getInputStream(), outputStream);
      // }


      if (p.waitFor() != 0) {
        throw new ServletException("tx conversion failed");


      }
    } catch (Exception e) {
      logger.severe(String.format("failed conversion input file: %s", inputFile.getAbsolutePath()));


      throw new ServletException("conversion failed", e);


    }
    logger.info("end tx begin " + inputFile.getAbsolutePath());


  }

  public static String MungPass(String pass) {
    try {
      MessageDigest m = MessageDigest.getInstance("MD5");




      byte[] data = pass.getBytes();
      m.update(data, 0, data.length);
      BigInteger i = new BigInteger(1, m.digest());




      return String.format("%1$032X", i);




    } catch (Exception e) {
      return pass.hashCode() + "";












    }




  }
}

class StreamGobbler implements Runnable {

  String name;
  InputStream is;
  Thread thread;

  public StreamGobbler(String name, InputStream is) {
    this.name = name;
    this.is = is;
  }

  public void start() {
    thread = new Thread(this);
    thread.start();
  }

  public void run() {
    try {
      InputStreamReader isr = new InputStreamReader(is);
      BufferedReader br = new BufferedReader(isr);

      while (true) {
        String s = br.readLine();
        if (s == null) {
          break;
        }
        System.out.println("[" + name + "] " + s);
      }

      is.close();

    } catch (Exception ex) {
      System.out.println("Problem reading stream " + name + "... :" + ex);
      ex.printStackTrace();
    }
  }
}
